package com.cc.visitor.entity.wechat;

import com.cc.visitor.enums.DevMaterial;
import com.cc.visitor.utils.RestTemplateUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;

/**
 * 请求微信服务器获取客户二维码或者永久二维码都需要
 * 在请求中加入 access_token ，本类用于生成并返回 access_token
 * 本 access_token 同样是拿开发者相关信息请求微信服务器获得的
 * 本 token 默认有效期是7200 秒，并且每天有限制请求新的次数
 * 所以需要缓存起来，如果没有过期就不要向微信服务器请求新的了
 */
@Service
public class WxAccessToken {
    private static final Logger logger = LoggerFactory.getLogger("wxmp");
    @Autowired
    private RestTemplateUtils restTemplateUtils;
    // 获取微信服务号/订阅号 access_token 的 URL
    private static final String PLATFORM_TOKENURL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
    // 获取微信小程序 access_token 的 URL
    private static final String MINI_TOKENURL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
    private static WechatAccessToken at;
    private static WechatAccessToken miniAccessToken;
    private static final ObjectMapper mapper = new ObjectMapper();

    /**
     * 返回缓存的用于微信服务号和微信服务器通信的 access_token
     * 如果缓存的 token 过期则请求新的后再返回
     * @return
     */
    public String getAccessToken() {
        if(at == null||at.isExpired()) {
            System.out.println("缓存的 access_token 已经过期，即将开始请求新的 access_token");
            getNewAccessToken();
        }else {
            System.out.println("access_token = " + at.toString() + "，仍然有效，直接拿来使用。");
        }
        return at.getAccess_token();
    }

    /**
     * 返回缓存的用于小程序和微信服务器通信的 access_token
     * 如果缓存的 token 过期则请求新的后再返回
     * @return
     */
    public String getMiniAccessToken() {
        if(miniAccessToken == null||miniAccessToken.isExpired()) {
            System.out.println("缓存的 mini access_token 已经过期，即将开始请求新的 access_token");
            getNewAccessToken();
        }else {
            System.out.println("缓存的 mini access_token = " + at.toString() + "，仍然有效。");
        }
        return miniAccessToken.getAccess_token();
    }

    /**
     * 请求新的小程序 access_token
     */
    private void getNewMiniAccessToken() {
        String url = MINI_TOKENURL.replace("APPID",DevMaterial.VISITOR_MINI.APPID).replace("APPSECRET", DevMaterial.VISITOR_MINI.APPSECRET);
        String szToken = restTemplateUtils.get4Object(url,String.class);
        System.out.println("请求新mini access_token 得到的响应结果：" + szToken);
        JavaType jvt = mapper.getTypeFactory().constructParametricType(HashMap.class,String.class,String.class);
        Map<String,String> jsonObject = null;
        try {
            jsonObject = mapper.readValue(szToken, jvt);
        } catch (JsonProcessingException e) {
            logger.info("解析微信服务器响应来的accessToken为实体对象时出现异常","WxAccessToken#getNewAccessToken");
            throw new RuntimeException(e);
        }
        String access_token="";
        String expire_in = "";
        try {
            access_token = jsonObject.get("access_token");
            expire_in = jsonObject.get("expires_in");
            logger.info("请求来新的 mini access_token:" + access_token + ",expire_in" + expire_in,"WxAccessToken#getNewAccessToken");
        } catch (Exception e) {
            String errCode = jsonObject.get("errcode");
            StringBuilder sb = new StringBuilder();
            switch (errCode) {
                case "40164":
                    sb.append(jsonObject.get("errmsg"));
                    System.out.println(sb.toString());
                    System.out.println("请将上面IP地址添加到白名单中。");
                    logger.info("请将IP地址"+sb+"添加到白名单中","WxAccessToken#getNewAccessToken#catch");
                    return;
                default:
                    System.out.println("向微信服务器请求新的 access_token 时出现异常！");
                    logger.info("请求新token报错误代码：" + errCode,"WxAccessToken#getNewAccessToken#catch");
                    break;
            }
        }
        miniAccessToken = new WechatAccessToken(access_token, expire_in);
    }

    /**
     * 请求新的微信服务号 access_token
     */
    private void getNewAccessToken() {
        String url = PLATFORM_TOKENURL.replace("APPID", DevMaterial.SHOWA_SERV.APPID).replace("APPSECRET", DevMaterial.SHOWA_SERV.APPSECRET);
        String szToken = restTemplateUtils.get4Object(url,String.class);
        System.out.println("请求微信服务器wechat token得到的响应结果是：" + szToken);
        logger.info("请求微信服务器accessToken的响应结果：" + szToken);
        JavaType jvt = mapper.getTypeFactory().constructParametricType(HashMap.class,String.class,String.class);
        Map<String,String> jsonObject = null;
        try {
            jsonObject = mapper.readValue(szToken, jvt);
        } catch (JsonProcessingException e) {
            logger.info("解析微信服务器响应来的accessToken为实体对象时出现异常","WxAccessToken#getNewAccessToken");
            throw new RuntimeException(e);
        }
        String access_token="";
        String expire_in = "";
        try {
            access_token = jsonObject.get("access_token");
            expire_in = jsonObject.get("expires_in");
            logger.info("请求了新token:" + access_token + ",expire_in" + expire_in,"WxAccessToken#getNewAccessToken");
        } catch (Exception e) {
            String errCode = jsonObject.get("errcode");
            StringBuilder sb = new StringBuilder();
            switch (errCode) {
                case "40164":
                    sb.append(jsonObject.get("errmsg"));
                    System.out.println(sb.toString());
                    System.out.println("请将上面IP地址添加到白名单中。");
                    logger.info("请将IP地址"+sb+"添加到白名单中","WxAccessToken#getNewAccessToken#catch");
                    return;
                default:
                    System.out.println("向微信服务器请求新的 access_token 时出现异常！");
                    logger.info("请求新token报错误代码：" + errCode,"WxAccessToken#getNewAccessToken#catch");
                    break;
            }
        }
        at = new WechatAccessToken(access_token, expire_in);
    }
}
